(function () {
    'use strict';

    var global = tinymce.util.Tools.resolve('tinymce.PluginManager');
    var DOMUtils = tinymce.util.Tools.resolve('tinymce.dom.DOMUtils');
    var $ = tinymce.util.Tools.resolve('tinymce.dom.DomQuery');

    var popupTpl = `<div id="J_cfyun_atwho" class="cfyun-atwho" style="position:absolute;padding:0px;min-width:150px;max-width:180px;min-height:18px;border:1px solid #eee;background:#fff">
        <style>
            .cfyun-atwho-search{margin: 10px;}
            .cfyun-atwho-tip, .cfyun-atwho-tips{text-align: center;padding:5px 10px;color: #07f;}
            .cfyun-atwho-tips{color: #636b6f;}
            .cfyun-atwho-list{max-height: 300px;overflow: hidden;border-top: 1px solid #eee;}
            .cfyun-atwho-list ul{height: 100%;overflow-y: auto;}
            .cfyun-atwho-list ul::-webkit-scrollbar {width: 6px;display: none}
            .cfyun-atwho-list ul:hover::-webkit-scrollbar {display: block;}
            .cfyun-atwho-list ul::-webkit-scrollbar-thumb {border-radius: 3px;background: #ccd0d7}
            .cfyun-atwho-list-item{padding: 3px 10px;border-bottom: 1px solid #f8f8f8;user-select: none;-webkit-user-select: none;overflow: hidden;display: -webkit-box;-webkit-box-orient: vertical;-webkit-line-clamp: 1;}
            .cfyun-atwho-list-item.hover,.cfyun-atwho-list-item:hover{background-color: #E8F3FC;}
            .cfyun-atwho-list-item:last-child{border: 0;}
        </style>
        <div class="cfyun-atwho-wrap">
            <div class="cfyun-atwho-tip">想用@提到谁？</div>
            <div class="cfyun-atwho-list"></div>
        </div>
    </div>`;

    class AtWho {
        constructor(editor) {
            
            if (!editor.getParam('cfyun_atwho', !1, 'boolean')) {
                return;
            }
            
            this.runtime = {
                at: editor.getParam('atwho_at', '@', 'string'),
                lindex: -1,
                cache: [],
                gspan: null,
                popup: null,
                enter: !1,
                isOpen: !1,
                imMode: !1,
                replaceAt: !1,
                queryTimer: null,
                errorTimer: null,
            };
            
            this.editor = editor;
            this.win = editor.getWin();
        	this.doc = editor.getDoc();
            // 最多艾特多少个用户
            this.maxNum = editor.getParam('atwho_max_num', 10, 'number');
            // 在不输入的情况查询好友列表
            this.queryAll = editor.getParam('atwho_query_all', !1, 'boolean');
            // 名字最多长度
            this.maxName = editor.getParam('atwho_max_name', 16, 'number');
            // 查询延时时间
            this.queryDelay = editor.getParam('atwho_query_delay', 200, 'number');
            // 查询回调, 需要实现ajax获取数据返回给本接口
            this.queryCallback = editor.getParam('atwho_query_callback', null, 'function');
            // 已选数据列表回调
            this.dataCallback = editor.getParam('atwho_data_callback', null, 'function');

            var _this = this;
            
            this.event();

            return this;
        };
        /**
         * 监听编辑器输入
         */
        event() {
            var _this = this;
            this.editor.on('click', function (e) {
                if(_this.runtime.isOpen === true) {
                    return !1;
                }

                var node = _this.editor.selection.getNode();
                
                if(
                    !$(node).hasClass('atwho') ||
                    !node.lastChild.nodeValue ||
                    (node.lastChild.nodeValue.split(_this.runtime.at)).length <= 1
                ) {
                    return !1;
                }

                var span = node;

                $(node).parents().find('span.atwho').removeClass('atwho-wait');

                // 还原
                if(node.tagName === 'A' && node.className == 'atwho') {
                    span = $('<span class="atwho">@</span>');
                    $(node).replaceWith(span);
                    span = span[0];
                } else {
                    _this.runtime.replaceAt = !0;
                }
                _this.runtime.replaceAt = !0;

                $(span).addClass('atwho-wait');

                /*
                if(node.lastChild.nodeValue != _this.runtime.at) {
                    return !1;
                }*/

                var x = span.getBoundingClientRect().left;
                var y = span.getBoundingClientRect().top;

                _this.show(x, y);
                _this.getDataForCache();
                return !1;
            });
            
            this.editor.on('keydown', function (e) {
                if(_this.runtime.queryTimer) {
                    // clearTimeout(_this.runtime.queryTimer);
                }
                var keyCode = e.which || e.keyCode;
                _this.runtime.imMode = e.shiftKey && (e.key == 'Process' || keyCode == 229 || keyCode == 197);

                if (_this.win.getSelection) {
                    var sel = _this.win.getSelection();
                    var rng = sel.getRangeAt(0);
                } else {
                    var sel = _this.doc.selection;
                    var rng = sel.createRange();
                }

                if(e.shiftKey && e.key == '@') {
                    if(_this.isCreateAt()) {
                        return !1;
                    }

				    _this.createAt();
                    e.preventDefault();
                // } else if (_this.runtime.enter && e.key == 'Enter') {
                } else if (_this.runtime.enter && e.key == 'End') { // 没办法这里只能用End插入, 因为tinymce的Enter被强制绑定的事件无法取消
                // } else if (_this.runtime.enter && (e.altKey == !0 && e.key == 'z')) {
                    _this.replaceUser();
                    e.preventDefault();
                    e.isDefaultPrevented();
                } else if(/*e.code == 'Space' || */e.key == 'Enter' || e.key == 'Tab') {
                    _this.hide();
                    _this.reset();
                } else if(e.key == 'Backspace') {
                    if(rng.startContainer.parentElement) {
					    var node = rng.startContainer.parentElement;
                        if(node && node.className == 'atwho' || node.className == 'atwho atwho-wait') {
                            var name = '';
                            if(node.innerHTML) {
                                name = node.innerHTML.substr(1);
                            }
                            // 剩下一个字符再删除
                            if(name.length < 1 || node.tagName === 'A') {
                                node.parentElement.removeChild(node);
                                sel.removeAllRanges();
                                sel.addRange(rng);
                                _this.callbackData();
                                // e.preventDefault();
                                return !1;
                            }
                        }
                    } else {
                        _this.hide();
                    }
                } else if(_this.runtime.isOpen && e.key == 'ArrowUp') {
                    _this.directionKey(-1);
                    e.preventDefault();
                } else if(_this.runtime.isOpen && e.key == 'ArrowDown') {
                    _this.directionKey(1);
                    e.preventDefault();
                }
            });
            
            this.editor.on('keyup', function (e) {
                if (_this.win.getSelection) {
                    var sel = _this.win.getSelection();
                    var rng = sel.getRangeAt(0);
                } else {
                    var sel = _this.doc.selection;
                    var rng = sel.createRange();
                }
                
                // 非英文输入模式
                if(_this.runtime.imMode) {
                    if(!_this.isCreateAt()) {
                        var node = rng.startContainer;

                        if(node && node.nodeValue != null) {
                            var len = node.length;
                            var str = node.nodeValue.substr(len - 1, 1);
                            if(str == _this.runtime.at) {
                                rng.setStart(node, len - 1);
                                rng.setEnd(node, len);
                                rng.deleteContents();
                                _this.createAt();
                            }
                        }
                    }
                }

                if(!_this.runtime.gspan) {
                    return !1;
                }

                if(_this.runtime.errorTimer){
                    clearTimeout(_this.runtime.errorTimer);
                }
                
                if (_this.runtime.isOpen && _this.runtime.gspan != null) {
                    if (e.key == 'ArrowUp' || e.key == 'ArrowLeft' || e.key == 'ArrowRight' || e.key == 'ArrowDown' || e.key == 'Shift') {
                        return !1;
                    }

                    var _gval = '';
                    if(_this.runtime.gspan.innerHTML) {
                        _gval = _this.runtime.gspan.innerHTML.substr(1);
                    }

                    // 超出截取
                    if(_gval && _gval.length >= _this.maxName) {
                        _gval = _gval.slice(0, _this.maxName);
                        return !1;
                    }

                    if(e.key == 'Backspace') {
                        if(_this.runtime.gval == '') {
                            _this.reset();
                            return !1;
                        }
                        
                        if ($('#J_cfyun_atwho').length) {
                            $('#J_cfyun_atwho').css('display', 'block');
                        }
                    }

                    // 直接查询所有
                    if(_gval === '' && _this.queryAll === !0) {
                        _gval = 'all';
                        _this.runtime.gval = '';
                    }
                    
				    if(_this.runtime.isOpen && _gval != '') {
                        if(_gval !== 'all') {
                            _this.runtime.gval = _gval;
                        }

                        _this.getDataForCache();

                        // 延时查询
                        _this.runtime.queryTimer = setTimeout(function() {
                            _this.getData();
                        }, _this.queryDelay);

                    }
                }
                e.preventDefault();
            });
            
            this.editor.on('mousedown', function (e) {
                _this.hide();
            });
        };
        /**
         * 是否创建at节点
         */
        isCreateAt() {
            var node = this.editor.selection.getNode();
            if(this.maxNum != 0 && this.count() >= this.maxNum) {
                return !0;
            }

            var isHas = $(node).hasClass('atwho');
            /*
            if(isHas && ($(node).html().split(this.runtime.at)).length > 2) {
                this.runtime.gspan = null;
                this.hide();
                $(node).replaceWith($(node).html());
            }
            */
            return isHas;
        };
        /**
         * 创建at节点
         */
        createAt() {
            if (this.win.getSelection) {
                var sel = this.win.getSelection();
                var rng = sel.getRangeAt(0);
            } else {
                var sel = this.doc.selection;
                var rng = sel.createRange();
            }

            var id = 'J_atwho_tmp' + (+new Date());
            this.addAt('<span class="atwho atwho-wait" id="' + id + '">@</span>');
            var span = this.doc.getElementById(id);

            this.runtime.gspan = span;

            var x = span.getBoundingClientRect().left;
            var y = span.getBoundingClientRect().top;

            var ospan = span.firstChild;
            rng.setStart(ospan, 1);
            rng.setEnd(ospan, 1);
            sel.removeAllRanges();
            sel.addRange(rng);
            
            this.show(x, y);
        };
        /**
         * 显示at用户的窗口
         */
        show(x, y) {
            var st = document.documentElement.scrollTop + document.body.scrollTop;
            var content = this.editor.iframeElement;
            var x0 = content.getBoundingClientRect().left + 11;
            var y0 = content.getBoundingClientRect().top + 20 + st;

            var popup;
            if (document.querySelectorAll('#J_cfyun_atwho').length) {
                popup = document.querySelectorAll('#J_cfyun_atwho')[0];
                popup.style.display = 'block';
            } else {
                popup = $(popupTpl)[0];
                $(document.body).append(popup);
            }

            popup.style.left = x + x0 + 'px';
            popup.style.top = y + y0 + 'px';
            this.runtime.isOpen = !0;
            this.runtime.popup = popup;
        };
        /**
         * 隐藏艾特用户窗口
         */
        hide() {
            if(this.runtime.popup) {
                this.runtime.isOpen = !1;
                this.runtime.popup.style.display = 'none';
            }
        };
        /**
         * 插入at用户
         */
        addUser(user) {
            var node = this.editor.selection.getNode();

            if(node.tagName == 'P') {
                node = $(node).find('span.atwho.atwho-wait')[0];
                // this.runtime.replaceAt = !0;
            }

            if(this.runtime.replaceAt) {
                var _node = node.lastChild;
                /*
                if(_node && _node.nodeValue != null && _node.nodeValue.indexOf(this.runtime.at) != -1) {
                    this.removeUser(_node.nodeValue.replace(this.runtime.at, ''));
                }*/
            }
            
            $(node).replaceWith(`<a class="atwho" data-uid="${user.uid}" href="${user.url}">@${user.name}</a>${(this.runtime.replaceAt ? '' : '&nbsp;')}`);
            
			this.hide();
            this.editor.focus();

            if(this.runtime.replaceAt) {
                this.runtime.replaceAt = !1;
            }
            
            this.callbackData();
        };
        replaceUser() {
			if(this.runtime.lindex == -1 || !this.usableUser) {
				return !1;
			}

            this.addUser(this.usableUser);
        };
        callbackData() {
            let _this = this;

            let list = [];
            let atList = $(this.editor.getBody()).find('.atwho');

            if(atList.length) {
                $.each(atList, function(i, value) {
                    var $this = $(value);
                    list.push({
                        uid: $this.attr('data-uid'),
                        name: $this.text().replace(_this.runtime.at, ''),
                        url: $this.attr('href')
                    });
                });
            }

            // 设置回调方法后, 则不设置监听事件回调方式
            if(typeof this.dataCallback == 'function') {
                this.dataCallback(list);
                return !1;
            }

            this.editor.fire('atwho', {list: list});
        };
        count() {
            return $(this.editor.getBody()).find('.atwho').length || 0;
        };
        /**
         * 填充好友列表
         */
        fillUserTpl(list) {
            var li = '', node = this.editor.selection.getNode();
            if(node.innerHTML && node.className == "atwho atwho-wait") {
                var keyword = node.innerHTML;
                keyword = keyword.substr(1, keyword.length);
            }

            if(keyword) {
                list = this.search(list, 'username', keyword);
            }
        
            for (var i = 0; i < list.length; i++) {
                var name = list[i].username;
                if(keyword && name && name.indexOf(keyword) != -1) {
                    name = name.replace(keyword, `<strong style="color: #07f">${keyword}</strong>`);
                }

                li += `<li class="cfyun-atwho-list-item" data-url="${list[i].url}" data-uid="${list[i].uid}">${name}</li>`;
            }
            $(this.runtime.popup).find('.cfyun-atwho-list').html(`<ul>${li}</ul>`);
            this.addUserEvent();
        };
        /**
         * 根据输入获取好友
         */
        getData() {
            if((!this.runtime.gval || this.runtime.gval == '') && this.queryAll !== !0) {
                return !1;
            }

		    this.showTips(!0, '加载中...');

            var _this = this;
            // 使用回调获取好友列表
            this.queryCallback(this.runtime.gval, (list) => {
                if(!list || !list.length) {
                    // 查找不到用户
                    var node = _this.editor.selection.getNode();
                    if(!node) {
                        return !1;
                    }
                    // 未包含.时
                    if(node.innerHTML && node.innerHTML.indexOf('.') === -1) {
                        _this.showTips(!0, '没有您要找的用户');
                        _this.runtime.errorTimer = setTimeout(() => {
                            _this.hide();
                        }, 1500);
                    } else {
                        // 输入包含.可能是要输入邮箱, 则恢复@符
                        if(node.className == 'atwho' || node.className == 'atwho atwho-wait') {
                            _this.hide();
                            _this.runtime.gspan = null;
                            $(node).replaceWith($(node).html());
                        }
                    }
                    return !1;
                }
		        _this.showTips(!1);
                _this.fillUserTpl(list);
                _this.runtime.cache.push({
                    key: _this.runtime.gval,
                    items: list
                });
            });
        };
        getDataForCache() {
            if(this.runtime.cache.length >= 1) {
                for(var i = 0,len = this.runtime.cache.length;i < len;i++) {
                    if(this.runtime.gval == this.runtime.cache[i].key) {
                        this.fillUserTpl(this.runtime.cache[i].items);
                        return false;
                    }
                }
            }
        };
        showTips (isShow, msg) {
            var tips = $(this.runtime.popup).find('.cfyun-atwho-list');

            if(msg) {
                tips.html(`<div class="cfyun-atwho-tips">${msg}</div>`);
                return !1;
            }
            tips.find('.cfyun-atwho-tips').remove();
        };
        directionKey(i) {
            if(!this.runtime.popup) {
                return !1;
            }

            var lis = $(this.runtime.popup).find('.cfyun-atwho-list li');

            if(!lis.length) {
                return !1;
            }

            var l = lis.length - 1;

            // 方向键控制
            if (i == -1) {
                this.runtime.lindex = this.runtime.lindex <= -1 ? l : this.runtime.lindex - 1;
            } else {
                this.runtime.lindex = this.runtime.lindex >= l ? -1 : this.runtime.lindex + 1;
            }

            lis.removeClass('hover');

            if (this.runtime.lindex != -1) {
                this.hover(this.runtime.lindex);
            } else {
                this.usableUser = {};
                this.runtime.enter = !1;
            }
        };
        hover(index) {
            if(!this.runtime.popup) {
                return !1;
            }

            this.runtime.lindex = index;
            this.runtime.enter = !0;

            var current = $(this.runtime.popup).find('.cfyun-atwho-list li').eq(index);

            current.addClass('hover');

            this.usableUser = {
                name: current.html(),
                uid: current.attr('data-uid'),
                url: current.attr('data-url'),
            };
        };
        /**
         * 监听插入at用户事件
         */
        addUserEvent() {
            var _this = this;

            if(!this.runtime.popup) {
                return !1;
            }

            $(this.runtime.popup).find('.cfyun-atwho-list li').off('click').on('click', function(e) {
                var $this = $(this);
                var name = $this.text().trim();
                var uid = $this.attr('data-uid');
                var url = $this.attr('data-url');

                _this.addUser({
                    uid: uid,
                    name: name,
                    url: url
                });
            });
        };
        /**
         * 插入at节点
         */
        addAt(html) {
            if (!this.doc.selection) {
                var sel = this.win.getSelection();
                var rng = sel.getRangeAt(0);
                var fragment = rng.createContextualFragment(html);
                rng.insertNode(fragment);
            } else {
                var range = this.doc.selection.createRng();
                range.pasteHTML(html);
            }
        };
        search(array, type, value) {
            if(!$.isArray(array)) {
                return !1;
            }

            var arr = [];
            arr = array.filter(function(a) {
                return a[type].toString().indexOf(value) != -1;
            });

            return arr;
        };
        /**
         * 重置
         */
        reset() {
            this.hide();
            $(this.runtime.popup).remove();
            this.runtime.lindex = -1;
            this.runtime.gspan = null;
            this.runtime.gval = null;
            this.runtime.popup = null;
            this.runtime.enter = !1;
            this.runtime.isOpen = !1;
            this.runtime.imMode = !1;
            this.runtime.replaceAt = !1;
            this.runtime.queryTimer = null;
            this.runtime.errorTimer = null;
        };
    }

	function Plugin () {
		global.add('atwho', function (editor) {
            editor.on('init', function (e) {
                new AtWho(editor)
            });
		});
	}

	Plugin();

}());
